/**
 * PHOSIDE: PHosphorylation Site IDentification Engine.
 * Copyright 2009 Digital Biology Lab, University of Missouri.
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version. <p/> This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more
 * details.
 */

package phoside.classify;

import phoside.data.feature.model.Instance;

import java.io.Serializable;

import java.util.List;
import java.util.ArrayList;

/**
 *
 * @author gjj
 */
public class AverageBoostingBinaryClassifier implements BoostingBinaryClassifier, Serializable {
    private static final long serialVersionUID = 4961850812349688572L;

    protected final List<BinaryClassifier> classifiers;

    public AverageBoostingBinaryClassifier() {
        this(new ArrayList());
    }

    public AverageBoostingBinaryClassifier(final List<BinaryClassifier> classifiers) {
        if (classifiers==null) {
            throw new NullPointerException();
        }
        
        this.classifiers = classifiers;
    }

    /**
     *
     * @param instances
     * @return a List of predicted values
     */
    public List<Double> classify(final List<Instance> instances) {
        if (instances==null) {
            throw new NullPointerException();
        }
        
        if (classifiers==null) {
            throw new java.lang.IllegalStateException("No classifier was added");
        }
        
        int ni = instances.size();
        
        //double[] sum = new double[ni];
        
        int nc = classifiers.size();
        List<Double>[] res = new List[nc];

        for (int i=0; i<nc; i++) {
            BinaryClassifier classifier = classifiers.get(i);
            res[i] = classifier.classify(instances);
        }

        List<Double> ret = new ArrayList(ni);
        for (int i=0; i<ni; i++) {
            double sum = 0;
            for (int j=0; j<nc; j++) {
                sum += res[j].get(i);
            }
            ret.add(sum/nc);
        }

        return ret;
    }

    /**
     *
     * @param instances
     * @param positive
     * @return
     */
    public boolean train(final List<Instance> instances, final List<Double> label) {
        if (instances==null || label==null) {
            throw new NullPointerException();
        }

        if (classifiers==null) {
            throw new java.lang.IllegalStateException("Add at least one classifier first");
        }

        for (BinaryClassifier classifier : classifiers) {
            if (!classifier.train(instances, label)) {
                return false;
            }
        }

        return true;
    }


    /**
     *
     * @return
     */
    public boolean addClassifier(final BinaryClassifier classifier) {
        if (classifier==null) {
            throw new NullPointerException();
        }

        return classifiers.add(classifier);
    }

    /**
     *
     * @return
     */
    public boolean removeClassifier(final BinaryClassifier classifier) {
        if (classifier==null) {
            throw new NullPointerException();
        }

        return classifiers.remove(classifier);
    }

    /**
     *
     */
    public void removeAllClassifiers() {
        classifiers.clear();
    }
}
